Skip to content

Vue2 与 Vue3 中组件传值核心知识点对比

一、Vue2 组件传值(Options API 形式)

Vue2 组件传值核心围绕「父子、隔代、兄弟」三类关系,不同关系对应不同传值方式,以下是面试高频的 6 种方式:

传值场景方式核心语法示例注意点
父 → 子(最常用)props父组件通过属性传值,子组件通过 props 接收父组件:
<Child :msg="parentMsg" :list="parentList" />
子组件:
props: {
msg: { type: String, default: '' },
list: { type: Array, default: () => [] }
}
1. props 是单向数据流(子不能直接修改);
2. 引用类型(数组/对象)修改内部值会同步到父组件(需避免);
3. 默认值为引用类型时需用函数返回(避免共享引用)
子 → 父(常用)自定义事件子组件 $emit 触发事件,父组件 v-on 监听子组件:
this.$emit('change', newVal)
父组件:
<Child @change="handleChange" />
methods: { handleChange(val) { ... } }
1. 事件名推荐 kebab-case(短横线);
2. 可传多个参数,父组件通过参数接收
子 → 父/父 → 子(双向绑定).sync 修饰符(语法糖)父组件:<Child :msg.sync="parentMsg" />
子组件:this.$emit('update:msg', newVal)
等价于:
<Child :msg="parentMsg" @update:msg="parentMsg = $event" />
Vue2.3+ 支持,本质是自定义事件的语法糖
隔代组件/兄弟组件(常用)EventBus 事件总线1. 创建总线:const bus = new Vue()
2. 发送:bus.$emit('eventName', val)
3. 接收:bus.$on('eventName', (val) => { ... })
4. 销毁:bus.$off('eventName')
兄弟组件 A 发送:bus.$emit('send', 'hello')
兄弟组件 B 接收:
created() { bus.$on('send', (val) => { ... }) }
beforeDestroy() { bus.$off('send') }
1. 需在组件销毁时解绑事件(避免内存泄漏);
2. 复杂场景易维护性差
隔代组件(面试高频)provide/inject父组件 provide 提供数据,子孙组件 inject 注入父组件:
provide() {
return { parentMsg: this.parentMsg }
}
子/孙组件:
inject: ['parentMsg']
1. 非响应式(Vue2 中需手动处理响应式);
2. 适用于隔代组件传值,不推荐大范围使用
任意组件(全局)Vuex1. 定义 state/mutations/actions
2. 取值:this.$store.state.xxx
3. 修改:this.$store.commit('mutationsName', val)
// store/index.js
export default new Vuex.Store({
state: { count: 0 },
mutations: { add(state) { state.count++ } }
})
组件中:this.$store.commit('add')
适用于复杂业务的全局状态管理,核心是「单向数据流」

二、Vue3 组件传值(组合式 API 为主,兼容选项式)

Vue3 兼容 Vue2 大部分传值逻辑,但在组合式 API(<script setup>)下语法有调整,同时新增 v-model 多绑定、Pinia 替代 Vuex 等特性:

传值场景方式核心语法示例注意点
父 → 子(常用)props父组件语法同 Vue2,子组件用 defineProps 接收父组件:
<Child :msg="parentMsg" />
子组件(setup):
const props = defineProps({
msg: { type: String, default: '' }
})
console.log(props.msg)
1. <script setup> 中 defineProps 无需导入;
2. props 仍是响应式,但不能解构(解构会丢失响应式)
子 → 父(常用)自定义事件子组件 defineEmits 声明事件,emit 触发;父组件监听子组件(setup):
const emit = defineEmits(['change'])
emit('change', newVal)
父组件:
<Child @change="handleChange" />
defineEmits 无需导入,事件名推荐 kebab-case
双向绑定(常用)v-model 多绑定(Vue3 增强)父组件:<Child v-model:msg="parentMsg" v-model:count="parentCount" />
子组件:
const props = defineProps(['msg', 'count'])
const emit = defineEmits(['update:msg', 'update:count'])
emit('update:msg', newMsg)
1. 替代 Vue2 的 .sync,支持多个 v-model;
2. 默认 v-model 对应 modelValue 属性 + update:modelValue 事件
隔代组件(面试高频)provide/inject(响应式增强)父组件:
import { provide, ref } from 'vue'
const msg = ref('hello')
provide('msg', msg)
子孙组件:
import { inject } from 'vue'
const msg = inject('msg')
1. 传递响应式数据(ref/reactive),子孙组件可直接使用;
2. 推荐只在父组件修改数据,子孙组件只读(保持单向数据流)
任意组件(全局)Pinia(替代 Vuex)1. 创建 store:
import { defineStore } from 'pinia'
export const useCountStore = defineStore('count', {
state: () => ({ count: 0 }),
actions: { add() { this.count++ } }
})
2. 组件中使用:
import { useCountStore } from '@/stores'
const store = useCountStore()
store.count // 取值
store.add() // 修改
1. Pinia 是 Vue3 官方推荐,替代 Vuex;
2. 无需 mutations,直接在 actions 中修改 state;
3. 支持组合式 API,更轻量
兄弟组件/隔代组件EventBus(Vue3 废弃)替代方案:Pinia / provide/inject-Vue3 移除 $on/$ off/$once,不推荐使用 EventBus

Vue3 组合式 API 传值完整示例

父组件(Parent.vue)

Plain

<template>
  <Child 
    :msg="parentMsg" 
    v-model:count="parentCount" 
    @change="handleChange"
  />
</template>

<script setup>
import { ref } from 'vue'
import Child from './Child.vue'

const parentMsg = ref('父组件传递的消息')
const parentCount = ref(0)

const handleChange = (val) => {
  console.log('子组件触发的事件:', val)
}
</script>

子组件(Child.vue)

Plain

<template>
  <div>{{ msg }}</div>
  <div>{{ count }}</div>
  <button @click="handleClick">修改值</button>
</template>

<script setup>
// 接收 props
const props = defineProps({
  msg: { type: String, default: '' },
  count: { type: Number, default: 0 }
})

// 声明自定义事件
const emit = defineEmits(['change', 'update:count'])

const handleClick = () => {
  // 触发自定义事件(子→父)
  emit('change', '子组件的消息')
  // 触发 v-model 双向绑定
  emit('update:count', props.count + 1)
}
</script>

三、Vue2 vs Vue3 组件传值核心差异

维度Vue2Vue3
核心语法Options API(props/emit 配置在选项中)组合式 API(defineProps/defineEmits 直接使用)
双向绑定.sync 修饰符v-model 多绑定(v-model:xxx),替代 .sync
全局状态管理Vuex(需区分 state/mutations/actions)Pinia(无需 mutations,更简洁)
EventBus基于 new Vue() 实现官方废弃,推荐 Pinia/provide/inject
provide/inject非响应式(需手动处理)天然支持响应式(传递 ref/reactive)
语法便捷性需在选项中声明 props/emit<script setup> 中 defineProps/defineEmits 无需导入,更简洁

总结

  1. 核心传值逻辑:Vue2/Vue3 父子组件传值核心仍是「props(父→子)+ 自定义事件(子→父)」,双向绑定语法有调整(.sync → v-model:xxx)。

  2. Vue3 关键变化:① 组合式 API 用 defineProps/defineEmits 替代选项式声明;② Pinia 替代 Vuex 做全局状态管理;③ 废弃 EventBus,推荐 Pinia/provide/inject 处理跨组件传值。

  3. 面试高频考点:① props 单向数据流的理解;② 子组件修改父组件数据的正确方式(emit/双向绑定);③ Vue3 中 v-model 多绑定的用法;④ Pinia 与 Vuex 的区别;⑤ provide/inject 的适用场景与响应式处理。

(注:文档部分内容可能由 AI 生成)

最近更新